feat(ci): add cross-platform final build checks#279
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: ProverCoderAI#278
Working session summaryDone. Updated existing PR 279 and marked it ready: Implemented:
Verified locally: Verified CI on latest SHA SOURCE: n/a. This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:
Total: (672.7K + 22.4M cached) input tokens, 61.0K output tokens, $31.863471 cost 🤖 Models used:
📎 Log file uploaded as Repository (83153KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
|
в Final build надо ещё проверить что запускается browser |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughЭтот PR добавляет кросс-платформенную поддержку: скрипт для пометки исполняемых файлов, замену bash-обёрток в npm-скриптах на прямой вызов Bun, ограничение refspec для зеркального refresh git до веток и тегов и новый CI workflow Final Build с проверками и упаковкой артефактов для Linux/macOS/Windows. ChangesCross-platform build and CI pipeline
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error)
✅ Passed checks (6 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/final-build.yml:
- Around line 27-33: The workflow .github/workflows/final-build.yml currently
only checks CLIs ("Verify docker-git CLI starts" and "Verify session sync CLI
starts"); add a new step after those that performs the requested browser/UI
clone smoke check by launching a headless browser and exercising the UI clone
path (open app served from the build, navigate to the clone UI/menu, trigger a
clone, and assert success). Name the step clearly (e.g., "Verify browser UI
clone smoke check") and implement it using your existing test runner or a
lightweight headless tool (Playwright/puppeteer or an npm script) so it starts
the built web app, runs the UI clone flow, and fails the job on error.
In `@packages/app/tests/docker-git/package-scripts-cross-platform.test.ts`:
- Around line 24-34: Add fast-check property-based assertions covering the same
invariants currently tested by the table-driven checks: the "no bash" invariant
for each launch script and the "no chmod" invariant for the package build
script. Use fast-check's fc.assert with an fc.property that generates indices or
script entries from the existing launchScripts array and validates that the
selected entry.script does not match /\bbash(?:\.exe)?\b/u (referencing
launchScripts and entry.scriptName/entry.packageName for contextual failure
messages), and another property that checks sessionSyncPackage.scripts.build
does not match /\bchmod\s+/u. Replace or augment the existing for-loop and
single expect with these fc.assert(fc.property(...)) calls so the test file
package-scripts-cross-platform.test.ts uses property-based testing for the
invariants.
In `@packages/lib/tests/core/templates.test.ts`:
- Around line 77-86: The test for "renderEntrypoint clone cache" is missing
negative assertions for pull-request and merge-request refspecs; update the spec
for the entrypoint returned by renderEntrypoint(makeTemplateConfig()) to assert
it does not contain the undesired refs by adding checks that entrypoint does not
contain "'+refs/pull/*:refs/pull/*'" and
"'+refs/merge-requests/*:refs/merge-requests/*'". Ensure you add these two
expect(...).not.toContain(...) assertions alongside the existing negative check
so the test prevents regressions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f798fdcc-08da-4eff-8545-a01201bd5aac
📒 Files selected for processing (11)
.changeset/cross-platform-final-build.md.github/actions/setup/action.yml.github/workflows/final-build.ymlpackage.jsonpackages/app/package.jsonpackages/app/src/lib/core/templates-entrypoint/tasks.tspackages/app/tests/docker-git/package-scripts-cross-platform.test.tspackages/docker-git-session-sync/package.jsonpackages/lib/src/core/templates-entrypoint/tasks.tspackages/lib/tests/core/templates.test.tsscripts/mark-executable.mjs
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/app/tests/docker-git/actions-project-create.test.ts`:
- Around line 94-137: Add property-based tests using fast-check to validate
invariants for the browser create project flow: create new tests that use
fc.assert(fc.property(...)) to vary projectId (fc.uuid()) and cursor
(fc.integer) and inside each property reset mocks
(eventStreamCloseMock.mockReset(), startCreateProjectMock.mockImplementation(()
=> Effect.succeed({ accepted: true, cursor, projectId }))), invoke the flow via
makeBrowserActionContext(), submitCreateInputs(...), and trigger the event
handler via readCreateEventHandler(); assert invariants: eventStreamCloseMock
called exactly once, the projectId returned by startCreateProjectMock equals the
id in the project.created event you trigger, and reloadDashboard (from context)
is called once after creation; place these tests alongside the existing
it.effect test and use the same helpers (submitCreateInputs,
readCreateEventHandler, startCreateProjectMock, eventStreamCloseMock,
reloadDashboard) so they run within the Effect test harness.
In `@packages/app/tests/docker-git/app-ready-create.test.ts`:
- Around line 98-120: Add a property-based test using fast-check that for any
valid repository URL with quickCreate:true the submitCreateInputs path and
invariants hold: use fc.property to generate valid repo URLs (and optional
branch segments), call submitCreateBuffer(..., { quickCreate: true }), then
assert submitCreateInputsMock was called once with a payload matching
CreateInputs (including repoUrl and repoRef) and that the repoUrl → outDir
invariant holds (compute expected outDir from the generated repo URL and compare
to the outDir in the mocked call); keep existing assertions around
requireCreateViewValue and createInitialFlowView and locate the test scaffolding
via submitCreateBuffer, submitCreateInputsMock, submitCreateInputs,
requireCreateViewValue, and createInitialFlowView.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 740fe432-8b4e-42b9-9fb6-0dba1356aba9
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (9)
.github/workflows/final-build.ymlpackage.jsonpackages/app/package.jsonpackages/app/tests/docker-git/actions-project-create.test.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/package-scripts-cross-platform.test.tspackages/docker-git-session-sync/package.jsonpackages/lib/tests/core/templates.test.tsscripts/final-build/browser-web-smoke.mjs
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: E2E (Clone cache)
- GitHub Check: E2E (Runtime volumes + SSH)
- GitHub Check: E2E (Clone auto-open SSH)
- GitHub Check: E2E (Login context)
- GitHub Check: E2E (OpenCode)
🧰 Additional context used
📓 Path-based instructions (6)
**/*
⚙️ CodeRabbit configuration file
**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.
Files:
scripts/final-build/browser-web-smoke.mjspackages/app/tests/docker-git/actions-project-create.test.tspackages/lib/tests/core/templates.test.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/docker-git-session-sync/package.jsonpackages/app/package.jsonpackages/app/tests/docker-git/package-scripts-cross-platform.test.tspackage.json
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Implement Functional Core, Imperative Shell (FCIS) pattern: CORE layer contains only pure functions with immutable data and mathematical operations; SHELL layer isolates all effects (IO, network, database). Strict dependency direction: SHELL → CORE (never reverse).
Never useany,unknown,eslint-disable,ts-ignore, orastype assertions (except in rigorously justified cases with documentation). Always use exhaustive union type analysis through.exhaustive()pattern matching.
All external dependencies must be wrapped through typed interfaces and injected via Effect-TS Layer pattern. Never call external services directly from CORE functions.
Use monadic composition with Effect-TS for all effects:Effect<Success, Error, Requirements>. Compose effects throughpipe()andEffect.flatMap(). Implement dependency injection via Layer pattern. Handle errors without try/catch blocks.
All functions must be pure in the CORE layer: no side effects (logging, console output, IO operations, mutations). Separate all side effects into the SHELL layer.
Use exhaustive pattern matching with Effect.Match instead of switch statements. Example:Match.value(item).pipe(Match.when(...), Match.exhaustive).
Document all functions with comprehensive TSDoc including:@pure(true/false),@effect(required services),@invariant(mathematical invariants),@precondition,@postcondition,@complexity(time and space),@throwsNever (errors must be typed in Effect).
Use functional comment markers for code clarity: CHANGE (brief description), WHY (mathematical/architectural justification), QUOTE(ТЗ) (requirement citation), REF (RTM or message ID), SOURCE (external source with quote), FORMAT THEOREM (∀x ∈ Domain: P(x) → Q(f(x))), PURITY (CORE|SHELL), EFFECT (Effect type signature), INVARIANT (mathematical invariant), COMPLEXITY (time/space).
Define all external service dependencies as Context.Tag classes with fully typed methods returning Effect types. Example: `class Da...
Files:
packages/app/tests/docker-git/actions-project-create.test.tspackages/lib/tests/core/templates.test.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/package-scripts-cross-platform.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: Implement property-based testing using fast-check for mathematical properties and invariants. Example:fc.property(fc.array(messageArbitrary), (messages) => isChronologicallySorted(sortMessagesByTimestamp(messages))).
Mock external dependencies in unit tests using Effect's testing utilities. Run tests without Effect runtime for speed. Example:Effect.provide(MockService), Effect.runPromise.
Files:
packages/app/tests/docker-git/actions-project-create.test.tspackages/lib/tests/core/templates.test.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/package-scripts-cross-platform.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Forbidden constructs in CORE code:any,eslint-disable,ts-ignore,async/await, raw Promise chains (then/catch),Promise.all,try/catchfor logic control,console.*, switch statements (use Match with .exhaustive() instead)
All functions must use Effect-TS for composing effects:Effect<Success, Error, Requirements>. No direct async/await, Promise chains, or try/catch in product logic.
Functional comments must include: CHANGE, WHY, QUOTE(ТЗ) or n/a, REF, SOURCE or n/a, FORMAT THEOREM, PURITY (CORE|SHELL), EFFECT signature for SHELL functions, INVARIANT, and COMPLEXITY.
All data mutations must use immutable patterns (ReadonlyArray, readonly properties, Object.freeze); mutation in SHELL only when absolutely necessary and documented.
Files:
packages/app/tests/docker-git/actions-project-create.test.tspackages/lib/tests/core/templates.test.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/package-scripts-cross-platform.test.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Property-based tests (fast-check) must verify mathematical invariants; unit tests must use Effect test utilities without async/await.
Files:
packages/app/tests/docker-git/actions-project-create.test.tspackages/lib/tests/core/templates.test.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/package-scripts-cross-platform.test.ts
package.json
📄 CodeRabbit inference engine (CLAUDE.md)
Dependencies must include Effect-TS (
effect: ^3.x) for monadic effects and@effect/schema: ^0.xfor validation with strong typing.Dependencies like effect (^3.x) and
@effect/schema(^0.x) are mandatory; project must enforce monadic composition through Effect.
Files:
package.json
🔇 Additional comments (6)
packages/lib/tests/core/templates.test.ts (1)
84-95: LGTM!packages/docker-git-session-sync/package.json (1)
13-13: LGTM!packages/app/package.json (1)
31-36: LGTM!Also applies to: 117-117
package.json (1)
26-28: LGTM!Also applies to: 39-39, 50-50
packages/app/tests/docker-git/package-scripts-cross-platform.test.ts (1)
25-37: LGTM!.github/workflows/final-build.yml (1)
1-51: LGTM!
| describe("browser create project action", () => { | ||
| beforeEach(() => { | ||
| eventStreamCloseMock.mockReset() | ||
| loadProjectDetailsMock.mockReset() | ||
| openProjectEventStreamMock.mockReset() | ||
| startCreateProjectMock.mockReset() | ||
| startCreateProjectMock.mockImplementation(() => | ||
| Effect.succeed({ | ||
| accepted: true, | ||
| cursor: 7, | ||
| projectId: project.id | ||
| }) | ||
| ) | ||
| openProjectEventStreamMock.mockImplementation(() => ({ close: eventStreamCloseMock })) | ||
| }) | ||
|
|
||
| it.effect("clones a project through the browser menu create flow", () => | ||
| Effect.gen(function*(_) { | ||
| const { context, output, reloadDashboard, setMessage } = makeBrowserActionContext() | ||
|
|
||
| submitCreateInputs(createInputs, context) | ||
|
|
||
| yield* _(waitForAssertion(() => { | ||
| expect(openProjectEventStreamMock).toHaveBeenCalledTimes(1) | ||
| })) | ||
| readCreateEventHandler()(projectCreatedEvent) | ||
|
|
||
| yield* _(waitForAssertion(() => { | ||
| expect(context.setSelectedProject).toHaveBeenCalledWith(project) | ||
| })) | ||
|
|
||
| expect(startCreateProjectMock).toHaveBeenCalledWith(expectedCreateDraft) | ||
| expect(openProjectEventStreamMock).toHaveBeenCalledWith(project.id, expect.objectContaining({ initialCursor: 7 })) | ||
| expect(eventStreamCloseMock).toHaveBeenCalledTimes(1) | ||
| expect(loadProjectDetailsMock).not.toHaveBeenCalled() | ||
| expect(reloadDashboard).toHaveBeenCalledTimes(1) | ||
| expect(context.setSelectedProjectId).toHaveBeenCalledWith(project.id) | ||
| expect(context.setSelectedMenuIndex).toHaveBeenCalledWith(1) | ||
| expect(setMessage).toHaveBeenLastCalledWith("Created octocat/Hello-World.") | ||
| expect(output()).toContain("[create] Project creation requested") | ||
| expect(output()).toContain("[create] Project accepted: project-1") | ||
| expect(output()).toContain("[create] Project created") | ||
| })) | ||
| }) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Рассмотрите добавление property-based тестов для инвариантов создания проекта.
Текущий тест правильно использует Effect-TS паттерны, но не проверяет инварианты через fast-check. Инварианты, подходящие для property-based тестирования:
- Любое успешное создание проекта должно закрывать event stream ровно один раз
projectIdиз ответа и из событияproject.createdвсегда совпадают- Dashboard reload всегда вызывается после успешного создания
Рекомендация: добавить fc.property тесты для этих инвариантов.
🧪 Пример property-based теста
it.effect("event stream always closes exactly once for any valid project creation", () =>
Effect.gen(function*(_) {
fc.assert(fc.property(
fc.uuid(),
fc.integer({ min: 1, max: 100 }),
(projectId, cursor) => {
eventStreamCloseMock.mockReset()
startCreateProjectMock.mockImplementation(() =>
Effect.succeed({ accepted: true, cursor, projectId })
)
submitCreateInputs(createInputs, context)
readCreateEventHandler()(/* trigger created event */)
expect(eventStreamCloseMock).toHaveBeenCalledTimes(1)
}
))
}))Согласно руководству по кодированию "**/*.test.{ts,tsx}: Implement property-based testing using fast-check for mathematical properties and invariants."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/app/tests/docker-git/actions-project-create.test.ts` around lines 94
- 137, Add property-based tests using fast-check to validate invariants for the
browser create project flow: create new tests that use
fc.assert(fc.property(...)) to vary projectId (fc.uuid()) and cursor
(fc.integer) and inside each property reset mocks
(eventStreamCloseMock.mockReset(), startCreateProjectMock.mockImplementation(()
=> Effect.succeed({ accepted: true, cursor, projectId }))), invoke the flow via
makeBrowserActionContext(), submitCreateInputs(...), and trigger the event
handler via readCreateEventHandler(); assert invariants: eventStreamCloseMock
called exactly once, the projectId returned by startCreateProjectMock equals the
id in the project.created event you trigger, and reloadDashboard (from context)
is called once after creation; place these tests alongside the existing
it.effect test and use the same helpers (submitCreateInputs,
readCreateEventHandler, startCreateProjectMock, eventStreamCloseMock,
reloadDashboard) so they run within the Effect test harness.
| it("submits a quick create clone from the Create menu", () => { | ||
| const { setCreateViewSpy } = submitCreateBuffer( | ||
| "https://github.com/octocat/Hello-World/tree/feature-x", | ||
| { quickCreate: true } | ||
| ) | ||
|
|
||
| expect(submitCreateInputsMock).toHaveBeenCalledTimes(1) | ||
| expect(submitCreateInputsMock.mock.calls[0]?.[0]).toEqual( | ||
| { | ||
| cpuLimit: "", | ||
| enableMcpPlaywright: false, | ||
| force: false, | ||
| forceEnv: false, | ||
| gpu: "none", | ||
| outDir: "/home/dev/.docker-git/octocat/hello-world", | ||
| ramLimit: "", | ||
| repoRef: "feature-x", | ||
| repoUrl: "https://github.com/octocat/Hello-World/tree/feature-x", | ||
| runUp: true | ||
| } satisfies CreateInputs | ||
| ) | ||
| expect(requireCreateViewValue(setCreateViewSpy.mock.calls[0]?.[0])).toEqual(createInitialFlowView()) | ||
| }) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Отсутствуют property-based тесты для инвариантов quick-create.
Согласно руководству по кодированию, тестовые файлы .test.ts должны использовать fast-check для проверки математических свойств и инвариантов. Текущий тест проверяет только один конкретный сценарий.
Рекомендация: добавить fc.property тесты, проверяющие, что для любого валидного URL репозитория с quickCreate: true функция submitCreateInputs вызывается с корректным CreateInputs payload и инвариант repoUrl → outDir сохраняется.
🧪 Пример property-based теста
+import * as fc from "fast-check"
+
+ it("quick create always produces valid CreateInputs for any repo URL", () => {
+ fc.assert(fc.property(
+ fc.webUrl({ withFragments: false, withQueryParameters: false }),
+ (repoUrl) => {
+ submitCreateInputsMock.mockReset()
+ const { setCreateViewSpy } = submitCreateBuffer(repoUrl, { quickCreate: true })
+
+ expect(submitCreateInputsMock).toHaveBeenCalledTimes(1)
+ const inputs = submitCreateInputsMock.mock.calls[0]?.[0]
+ expect(inputs?.repoUrl).toBeTruthy()
+ expect(inputs?.outDir).toBeTruthy()
+ }
+ ))
+ })Согласно руководству по кодированию "**/*.test.{ts,tsx}: Implement property-based testing using fast-check for mathematical properties and invariants."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/app/tests/docker-git/app-ready-create.test.ts` around lines 98 -
120, Add a property-based test using fast-check that for any valid repository
URL with quickCreate:true the submitCreateInputs path and invariants hold: use
fc.property to generate valid repo URLs (and optional branch segments), call
submitCreateBuffer(..., { quickCreate: true }), then assert
submitCreateInputsMock was called once with a payload matching CreateInputs
(including repoUrl and repoRef) and that the repoUrl → outDir invariant holds
(compute expected outDir from the generated repo URL and compare to the outDir
in the mocked call); keep existing assertions around requireCreateViewValue and
createInitialFlowView and locate the test scaffolding via submitCreateBuffer,
submitCreateInputsMock, submitCreateInputs, requireCreateViewValue, and
createInitialFlowView.
Summary
Final BuildGitHub Actions workflow for Ubuntu, macOS, and Windows that builds both packages, smoke-tests both CLIs, and uploads package tarballs.chmodwith a Bun helper.Reproduction and Verification
packages/app/tests/docker-git/package-scripts-cross-platform.test.tsbefore implementing the script changes.25728183189:E2E (Clone cache)timed out after1800son the second cache reuse case while refreshing broadrefs/*.packages/lib/tests/core/templates.test.tsproving mirror refreshes includerefs/heads/*andrefs/tags/*but not broadrefs/*.Local Checks
bun run --cwd packages/lib test -- tests/core/templates.test.tsbun run --cwd packages/app test -- tests/docker-git/package-scripts-cross-platform.test.tsbun run buildbun run typecheckbun run lintbun run lint:effectbun run check:dist-deps-prunebun run testgit diff --checkMathematical Guarantees
Invariants
forall os in {linux, macos, windows}: final-build(os) -> build(os) and cli_help(app, os) and cli_help(session_sync, os)forall r in clone_cache_refresh_refs: r in refs/heads/* union refs/tags/*forall npm_script in checked_scripts: not contains(npm_script, "bash -lc")Preconditions
Postconditions
refs/pull/*orrefs/merge-requests/*through broadrefs/*.Complexity
O(|all remote refs|)toO(|heads| + |tags|).SOURCE: n/a
Fixes #278